package br.cin.ufpe.feedbacktest.core;



public class Variable {

	/**
	 * Variable
	 * Name.
	 */
	private String name;

	/**
	 * Variable
	 * Type.
	 */
	private Class<?> type;
	
	/**
	 * Parameters Types
	 */
	private Class<?>[] parametersTypes;

	/**
	 * Parameters
	 * Values
	 */	
	private Object[] parametersValues;

	/**
	 * Runtime
	 * Value.
	 */
	private Object value;

	/**
	 * Flag to check if the
	 * value has been set. 
	 */
	private boolean set;

	/**
	 * Class
	 * Constructor
	 * 
	 * @param name variable name
	 */
	public Variable() {
		this.name = null;
		this.type = null;
		this.value = null;
		this.set = false;
	}

	/**
	 * Variable
	 * name Getter.
	 * 
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * Variable
	 * type Getter.
	 * 
	 * @return the type
	 */
	public Class<?> getType() {
		return type;
	}

	/**
	 * @param name the name to set
	 */
	public void setType(Class<?> type) {
		this.type = type;
	}

	/**
	 * Variable runtime
	 * value Getter.
	 * @return the value
	 */
	public Object getValue() {
		if (!set) {
			throw new RuntimeException("Variable value has not been set!");
		}
		return value;
	}	

	public Object[] getParametersValues() {
		return parametersValues;
	}

	public void setParametersValues(Object[] parametersType) {
		this.parametersValues = parametersType;
	}	

	public Class<?>[] getParametersTypes() {
		return parametersTypes;
	}

	public void setParametersTypes(Class<?>[] parametersTypes) {
		this.parametersTypes = parametersTypes;
	}

	/**
	 * @param value the value to set
	 */
	public void setValue(Object value) {
		this.value = value;
		this.set = true;
	}

	public boolean isPrimitive() {
		Class<?> valueClass = this.value.getClass();

		return (valueClass.equals(Byte.class)) ||
		(valueClass.equals(Short.class)) ||
		(valueClass.equals(Integer.class)) ||
		(valueClass.equals(Long.class)) ||
		(valueClass.equals(Float.class)) ||
		(valueClass.equals(Double.class)) ||
		(valueClass.equals(Boolean.class)) ||
		(valueClass.equals(Character.class)) ;
	}

	public void resetInstance() {
		try {
			//this.value = this.type.newInstance();
			this.value = RandomResolver.instantiateClass(this.type,this);
		} catch (Exception e) {			
			e.printStackTrace();
		}
	}

	public String toString() {
		if (name != null) {
			return name;

		} else if (value != null) {
			Class<?> valueClass = this.value.getClass();

			if ( (valueClass.equals(Byte.class)) ||
					(valueClass.equals(Short.class)) ||
					(valueClass.equals(Integer.class)) ||
					(valueClass.equals(Long.class)) ||
					(valueClass.equals(Float.class)) ||
					(valueClass.equals(Double.class)) ||
					(valueClass.equals(Boolean.class)) ) {

				return value.toString();

			} else if (valueClass.equals(Character.class)) {

				return "'" + value.toString() + "'";

			} else if( valueClass.isArray()){			
				return "new "+valueClass.getComponentType().getName()+"[]{}";
			}
			else {
				StringBuilder buffer = new StringBuilder();
				buffer.append("new ");
				buffer.append(valueClass.getName());
				if(parametersValues != null){
					buffer.append("(");
					if(parametersValues.length > 0){
						buffer.append(getParameterRepresentation(0));
						for(int index = 1; index < parametersValues.length;index++){
							buffer.append(",");
							buffer.append(getParameterRepresentation(index));
						}					
					}
					buffer.append(")");
				}else{
					buffer.append("()");
				}
				return buffer.toString();
			}

		} else {
			if (this.type.isArray()) {
				return "(" + this.type.getComponentType().getName() + "[])null)";
			} else {
				return "((" + this.type.getName() + ")null)";
			}

		}
	}
	
	private Object getParameterRepresentation(int index){
		Object obj = null;
		if(parametersTypes[index].isPrimitive()){
			obj = parametersValues[index].toString();
		}		
		else if(parametersTypes[index].equals(String.class)){
			obj = "\""+parametersValues[index].toString()+"\"";
		}
		else if(parametersTypes[index].equals(char.class)){
			obj = "'"+parametersValues[index].toString()+"'";
		}
		else if(parametersTypes[index].isArray()){
			obj = "new "+parametersValues[index].getClass().getComponentType().getName() +"[]{}";
		}
		else{			
			obj = ClassToString.parameterPrint(parametersTypes[index]);
		}
		
		return obj;
	}
	
	
}
